/*
 * pcicfg - PCI drivers & tools for accessing memory location, I/O ports and configuration space.
 * Copyright (C) 2013  Andrew Karasyov
 *
 * This library is free software: you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation, either 
 * version 3 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef _PCICFG_H_
#define _PCICFG_H_


#define PCICFG_MAJOR 200
#define PCICFG_MODNAME "pcicfg"

/** Use 'k' as magic number */
#define PCICFG_IOC_MAGIC  'k'


/**
 * S means "Set" through a ptr,
 * T means "Tell" directly with the argument value
 * G means "Get": reply by setting through a pointer
 * Q means "Query": response is on the return value
 * X means "eXchange": switch G and S atomically
 * H means "sHift": switch T and Q atomically
 */
#define PCICFG_IOCQDEVICECOUNT _IO(PCICFG_IOC_MAGIC, 0)
#define PCICFG_IOCGDEVICELIST  _IOR(PCICFG_IOC_MAGIC, 1, int)
#define PCICFG_IOCXCFGBYTE     _IOWR(PCICFG_IOC_MAGIC, 2, int)
#define PCICFG_IOCXCFGWORD     _IOWR(PCICFG_IOC_MAGIC, 3, int)
#define PCICFG_IOCXCFGDWORD    _IOWR(PCICFG_IOC_MAGIC, 4, int)
#define PCICFG_IOCXCFG4K       _IOWR(PCICFG_IOC_MAGIC, 5, int)
#define PCICFG_IOCSCFGBYTE     _IOW(PCICFG_IOC_MAGIC, 6, int)
#define PCICFG_IOCSCFGWORD     _IOW(PCICFG_IOC_MAGIC, 7, int)
#define PCICFG_IOCSCFGDWORD    _IOW(PCICFG_IOC_MAGIC, 8, int)
#define PCICFG_IOCSCFG4K       _IOW(PCICFG_IOC_MAGIC, 9, int)

#define PCICFG_IOC_MAXNR 9

/** Bus/Device:Function
 *  The bus/device/function is encoded in single word as follows:
 *  
 *  15:8  = bus      (range 0..255)
 *   7:3  = device   (range 0..31)
 *   2:0  = function (range 0..7)
 */
#define PCICFG_MAKE_BUSDEVFN(bus, dev, func) ((((bus) & 0xff) << 8 ) | (((dev) & 0x1f) << 3) | ((func) & 0x07))
#define PCICFG_MAKE_DEVFN(dev, func)	     ((((dev) & 0x1f) << 3) | ((func) & 0x07))
#define PCICFG_GET_BUS(busdevfn)             (((busdevfn) >> 8) & 0xff)
#define PCICFG_GET_DEV(busdevfn)		     (((busdevfn) >> 3) & 0x1f)
#define PCICFG_GET_FUNC(busdevfn)		     ((busdevfn) & 0x07)
#define PCICFG_GET_DEVFN(busdevfn)           ((busdevfn) & 0xff)

/** Global constants */
#define PCICFG_CFGSPACE_LENGTH_MAX_BYTES 4096

struct PCIDeviceDescription
{
	/** Device B:D:F */
	unsigned short BDF;
	
	unsigned short VendorID;
	
	unsigned short DeviceID;
	
	unsigned short SubsystemVendorID;
	
	unsigned short SubsystemDeviceID;
	
	unsigned int Class;
	
	unsigned char Revision;

	unsigned char HeaderType;
	
	unsigned char PcieCapabilityOffset;
	
	int PMCapabilityOffset;

	int CfgSpaceSize;
	
	/** Config space access is blocked */
	unsigned int IsCfgAccessBlocked : 1;
	
	/** Indicates if device is bridge */
	unsigned int IsBridge : 1;
	
	/* Indicates if device is transparent PCI bridge */
	unsigned int IsTransparentBridge : 1;

	/* Indicates that device is a part of multi-function device */
	unsigned int IsMultifunction : 1;

	/* Indicates if device is PCIE device */
	unsigned int IsPcie : 1;

	unsigned int Reserved : 3;
	
	/** Bus this device bridges to. Valid only if this is bridge. See IsBridge */
	unsigned char SubordinateBus;
};


struct PCIDeviceValue
{
	/** Device B:D:F */
	unsigned short BDF;
	
    /** Offset. Used for writing operation to store offset in config space */
    unsigned int Offset;

	/** This is 32 bit value. It can be accessed as bytes, words and dword.
	 *  It can also be a buffer. */
	union
	{
		struct
		{
			unsigned char Byte0;
			unsigned char Byte1;
			unsigned char Byte2;
			unsigned char Byte3;
		};
		
		struct
		{
			unsigned short Word0;
			unsigned short Word1;
		};
		
		unsigned int Dword;

		unsigned char* Buffer;
	};
};


#endif // _PCICFG_H_
